package lock.demo;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * Date: 2020-07-16
 * Time: 14:28
 *
 * @author zyh
 */
public class ZkLock implements AsyncCallback.StringCallback, Watcher, AsyncCallback.StatCallback,AsyncCallback.Children2Callback {


    private ZooKeeper zooKeeper;
    private CountDownLatch countDownLatch;
    private String threadName;
    private String rootName = "/lock";
    private String pathName;

    public ZkLock(ZooKeeper zooKeeper, String threadName) {
        this.zooKeeper = zooKeeper;
        this.threadName = threadName;
    }

    public void trylock() throws KeeperException, InterruptedException {

        this.countDownLatch = new CountDownLatch(1);
        this.zooKeeper.create(rootName + "/lock", threadName.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL, this, "create");
        try {
            this.countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void unlock() {
        //System.out.println("unlock"+pathName);
        try {

            this.zooKeeper.delete(pathName, -1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
        System.out.println(threadName + " unclock");
    }

    /**
     * create 回调
     *
     * @param rc
     * @param path
     * @param ctx
     * @param name
     */
    @Override
    public void processResult(int rc, String path, Object ctx, String name) {
//        System.out.println("String call back " + name);
//        System.out.println(threadName + "线程创建了" + name);
        pathName = name;
        this.zooKeeper.getChildren(rootName, false, this, "children");


    }

    @Override
    public void processResult(int rc, String path, Object ctx, List<String> children, Stat stat) {
        //System.out.println("get children ");
        String currPath = pathName.replace(rootName+"/","");
        children.sort((o1, o2) -> {
            int num1 = Integer.parseInt(o1.substring(4));
            int num2 = Integer.parseInt(o2.substring(4));
            return num1 - num2;
        });
        //System.out.println(children);
        int i = children.indexOf(currPath);

        if (i == 0) {
           // System.out.println("is first " + currPath);
            countDownLatch.countDown();
        } else {
//            System.out.println("is not first " + currPath);
//            System.out.println("watch "+rootName+"/"+ children.get(i - 1)+"exists");
            this.zooKeeper.exists(rootName+"/"+ children.get(i - 1), this,this,"exists");
        }

    }

    @Override
    public void process(WatchedEvent event) {
        Event.EventType type = event.getType();

        switch (type) {
            case None:
                break;
            case NodeCreated:
                break;
            case NodeDeleted:
                zooKeeper.getChildren(rootName, false, this, "delete");
                break;
            case NodeDataChanged:
                break;
            case NodeChildrenChanged:
                break;
            case DataWatchRemoved:
                break;
            case ChildWatchRemoved:
                break;
            default:
                break;
        }

    }

    @Override
    public void processResult(int rc, String path, Object ctx, Stat stat) {

        if(stat == null){
            zooKeeper.getChildren(rootName, false, this, "delete");
        }

    }
}
